/*****************************************************************************************
   
   Copyright (c) Microsoft Corporation. All rights reserved.

   Use of this code sample is subject to the terms of the Microsoft
   Public License, a copy of which should always be distributed with
   this file.  You can also access a copy of this license agreement at:
   http://www.microsoft.com/opensource/licenses.mspx#Ms-PL

 ****************************************************************************************/
using System;

namespace Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary
{
    public class BindingCollection
    {
        #region private variables

        private System.Collections.Generic.SortedList<string, Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding> m_BindingSortedList = new System.Collections.Generic.SortedList<string, Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding>();

        private Microsoft.CSA.FeedSync.FeedSyncLibrary.RSSFeed m_RSSFeed = null;

        private string m_NamespacePrefix;

        #endregion

        public BindingCollection(Microsoft.CSA.FeedSync.FeedSyncLibrary.RSSFeed i_RSSFeed) :
            this(i_RSSFeed, true)
        {
        }

        public BindingCollection(Microsoft.CSA.FeedSync.FeedSyncLibrary.RSSFeed i_RSSFeed, bool i_CreateDefaultTitleDescription)
        {
            if (i_RSSFeed == null)
                throw new System.ArgumentException("i_RSSFeed must be non-null!");

            m_RSSFeed = i_RSSFeed;

            m_NamespacePrefix = Microsoft.CSA.FeedSync.FeedSyncLibrary.XmlNamespaceManagerHelper.InitializeXmlNamespaceManager
                (
                m_RSSFeed.XmlDocument,
                m_RSSFeed.XmlNamespaceManager,
                Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Constants.SIMPLE_FEED_BINDINGS_XML_NAMESPACE_PREFIX,
                Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Constants.SIMPLE_FEED_BINDINGS_XML_NAMESPACE_URI
                );

            if (System.String.IsNullOrEmpty(m_NamespacePrefix))
                return;

            string XPathQuery = System.String.Format
                (
                "{0}:{1}",
                m_NamespacePrefix,
                Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Constants.BINDING_ELEMENT_NAME
                );

            //  See if SimpleFeedBindings exist
            System.Xml.XmlNodeList BindingXmlNodeList = i_RSSFeed.ChannelXmlElement.SelectNodes
                (
                XPathQuery,
                m_RSSFeed.XmlNamespaceManager
                );


            foreach (System.Xml.XmlElement BindingXmlElement in BindingXmlNodeList)
            {
                Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding Binding = new Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding
                    (
                    BindingXmlElement,
                    m_RSSFeed.XmlNamespaceManager,
                    i_CreateDefaultTitleDescription
                    );

                this.AddBinding(Binding, false);
            }
        }

        private string GetMappedNamespacePrefix(string i_PreferredNamespacePrefix, string i_NamespaceURI)
        {
            string MappedNamespacePrefix = i_PreferredNamespacePrefix;

            foreach (System.Collections.Generic.KeyValuePair<string, string> KeyValuePair in m_RSSFeed.XmlNamespaceManager.GetNamespacesInScope(System.Xml.XmlNamespaceScope.All))
            {
                if (KeyValuePair.Value != i_NamespaceURI)
                    continue;

                if (KeyValuePair.Key == i_PreferredNamespacePrefix)
                    break;

                //  Check for default namespace
                if (System.String.IsNullOrEmpty(KeyValuePair.Key))
                {
                    //  See if prefix used
                    if (m_RSSFeed.XmlNamespaceManager.HasNamespace(i_PreferredNamespacePrefix))
                    {
                        //  See if prefix is mapped to namespace uri
                        string NamespaceURI = m_RSSFeed.XmlNamespaceManager.LookupNamespace(i_PreferredNamespacePrefix);
                        if (NamespaceURI != i_NamespaceURI)
                        {
                            //  Create a new prefix
                            MappedNamespacePrefix = i_PreferredNamespacePrefix + System.Guid.NewGuid().ToString();
                        }
                    }

                    break;
                }
            }

            //  Add namespace with mapped prefix
            if (!m_RSSFeed.XmlNamespaceManager.HasNamespace(MappedNamespacePrefix))
            {
                m_RSSFeed.XmlNamespaceManager.AddNamespace
                    (
                    MappedNamespacePrefix,
                    i_NamespaceURI
                    );
            }

            return MappedNamespacePrefix;
        }

        public System.Collections.Generic.IList<Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding> Bindings
        {
            get
            {
                return m_BindingSortedList.Values;
            }
        }

        public bool HasBinding(string i_ID)
        {
            Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding Binding = null;
            return (this.FindBinding(i_ID, out Binding));
        }

        public bool FindBinding(string i_ID, out Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding o_Binding)
        {
            o_Binding = null;

            if (!m_BindingSortedList.ContainsKey(i_ID))
                return false;

            o_Binding = m_BindingSortedList[i_ID];

            return true;

        }

        public Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding GetBinding(string i_ID)
        {
            Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding Binding = null;

            if (!this.FindBinding(i_ID, out Binding))
                throw new System.ArgumentException("Invalid id: " + i_ID);

            return Binding; ;
        }

        public Microsoft.CSA.FeedSync.FeedSyncLibrary.RSSFeed RSSFeed
        {
            get
            {
                return m_RSSFeed;
            }

        }

        public string NamespacePrefix
        {
            get
            {
                return m_NamespacePrefix;
            }
        }

        public void AddBinding(Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding i_Binding, bool i_AppendXmlElement)
        {
            if (this.HasBinding(i_Binding.ID))
                throw new System.ArgumentException("Binding already exists!");

            if (i_Binding.XmlElement.OwnerDocument != m_RSSFeed.XmlDocument)
            {
                System.Xml.XmlElement ImportedBindingXmlElement = (System.Xml.XmlElement)m_RSSFeed.XmlDocument.ImportNode
                    (
                    i_Binding.XmlElement,
                    true
                    );

                i_Binding = new Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding
                    (
                    ImportedBindingXmlElement, 
                    i_Binding.XmlNamespaceManager,
                    i_Binding.DefaultTitleDescription
                    );
            }

            m_BindingSortedList[i_Binding.ID] = i_Binding;

            foreach (Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Namespace Namespace in i_Binding.Namespaces)
            {
                string MappedNamespacePrefix = this.GetMappedNamespacePrefix
                    (
                    Namespace.LocalPrefix,
                    Namespace.URI
                    );

                Namespace.SetMappedPrefix(MappedNamespacePrefix);
            }

            i_Binding.BindingCollection = this;

            if (i_AppendXmlElement)
                m_RSSFeed.ChannelXmlElement.AppendChild(i_Binding.XmlElement);
        }

        public void ReplaceBinding(string i_ID, Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding i_Binding)
        {
            if (System.String.IsNullOrEmpty(i_ID))
                throw new System.ArgumentException("i_ID must be non-null!");

            if (i_Binding == null)
                throw new System.Exception("i_Binding must be non-null!");

            Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding Binding;

            if (!this.FindBinding(i_ID, out Binding))
                throw new System.ArgumentException("Specified item does not exist!");

            Binding.XmlElement.ParentNode.RemoveChild(Binding.XmlElement);

            if (i_Binding.XmlElement.OwnerDocument != m_RSSFeed.XmlDocument)
            {
                System.Xml.XmlElement ClonedXmlElement = (System.Xml.XmlElement)m_RSSFeed.XmlDocument.ImportNode
                    (
                    i_Binding.XmlElement,
                    true
                    );

                i_Binding = new Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding
                    (
                    ClonedXmlElement,
                    m_RSSFeed.XmlNamespaceManager,
                    i_Binding.DefaultTitleDescription
                    );
            }

            m_RSSFeed.ChannelXmlElement.AppendChild(i_Binding.XmlElement);

            m_BindingSortedList[i_ID] = i_Binding;
        }

        public System.Collections.Generic.IList<Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding> GetMergeChangeList(Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.BindingCollection i_IncomingBindingCollection)
        {
            System.Collections.Generic.IList<Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding> MergedBindingList = Microsoft.CSA.FeedSync.FeedSyncLibrary.Sync.Merge<Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding>
                (
                this.Bindings,
                i_IncomingBindingCollection.Bindings
                );

            return MergedBindingList;
        }

        public void Merge(Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.BindingCollection i_IncomingBindingCollection)
        {
            System.Collections.Generic.IList<Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding> MergedBindingList = this.GetMergeChangeList(i_IncomingBindingCollection);

            //  Merge collections
            foreach (Microsoft.CSA.FeedSync.SimpleFeedBindingsLibrary.Binding MergedBinding in MergedBindingList)
            {
                if (this.HasBinding(MergedBinding.Sync.ID))
                {
                    this.ReplaceBinding
                        (
                        MergedBinding.Sync.ID,
                        MergedBinding
                        );
                }
                else
                {
                    this.AddBinding
                        (
                        MergedBinding,
                        true
                        );
                }
            }
        }

    }
}
